package Gui; 
 
import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED;
import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED;

import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import javax.swing.JSeparator;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import Triangulation.EdgeGenerator;
import Triangulation.minimalityMetrics.DelaunayMetric;
import Triangulation.minimalityMetrics.LongestBaseToHeightRatioMetric;
import Triangulation.minimalityMetrics.LongestBaseToHeightRatioMetricDiamond;
import Triangulation.minimalityMetrics.MinimalityMetric;
import Triangulation.minimalityMetrics.ShortestEdgesMetric;
import Triangulation.minimalityMetrics.UniformAnglesMetric;
import controller.Globals;
import datatypes.Vertex;


public class MainWindow extends JFrame
{ 
    private static final long serialVersionUID = 3940935757890529911L; 
 
//    public UserDrawWindow userInputWindow; 
    private TriangleDisplay triangulationWindow; 
    private JButton clearButton, randomGenerateButton; 
    private JPanel windowNorth, windowCenter; 
    private JComboBox triangulatersComboBox; 
    private JComboBox metricsComboBox;
    private Vector<Triangulation.EdgeGenerator> triangulaters; 
    private Vector<MinimalityMetric> metrics;
    private int activeTriangulater = 0; 
    private int activeMetric = 0;
    private RandomizePointsDialog randPointsDialog;
    private SaveVerticesDialog saveVertsDialog;
    private LoadVerticesDialog loadVertsDialog;
    private BottomPanel infoPanel;
    private Boolean showExtraInfo = true;
    private JComboBox displayModeComboBox;
    
    public static void main(String args[]) 
    { 
        try {
        	System.setProperty("apple.laf.useScreenMenuBar", "true");
        	System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Triangulator");
        	UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        	java.util.Locale.setDefault(java.util.Locale.ENGLISH);  
        }
        catch(Exception e) {
                 System.out.println("Error: " + e.getMessage());
        }
        
        new MainWindow("Optimal triangulation (Click to add points)", 1024, 512); 
    } 
 
    public MainWindow(String title, int width, int height) 
    { 
        super(title);
        
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        setSize(width, height);
        
        //Create the menu bar.
        JMenuBar menuBar = new JMenuBar();
        //
        //Build the  menu.
        //
        // File menu
        //
        JMenu fileMenu = new JMenu("File");
        menuBar.add(fileMenu);
        JMenuItem menuItem = new JMenuItem("Open...");
        fileMenu.add(menuItem);
        menuItem.addActionListener(new AbstractAction( "Load") {
        	private static final long serialVersionUID = 9140614429878493935L; 
            public void actionPerformed(ActionEvent e) 
            { 
                loadVerticesDialog(); 
            } 
        });
        
        menuItem = new JMenuItem("Save...");
        menuItem.addActionListener(new AbstractAction("Save") { 
        	private static final long serialVersionUID = 9140613519878493938L; 
        	
        	public void actionPerformed(ActionEvent e) 
        	{ 
        		saveVerticesDialog();
        	} 
        });
        
        fileMenu.add(menuItem);
        //
        // edit menu
        //
        JMenu editMenu = new JMenu("Edit");
        menuBar.add(editMenu);
        menuItem = new JMenuItem("Copy");
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));
        menuItem.addActionListener(new AbstractAction("Copy") { 
            /**
	     * 
	     */
	    private static final long serialVersionUID = 2133423860827611711L;

		public void actionPerformed(ActionEvent e) 
        	{ 
        		triangulationWindow.copySelectedVertices();
        	} 
        });
        editMenu.add(menuItem);
        menuItem = new JMenuItem("Paste");
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.CTRL_MASK));
        menuItem.addActionListener(new AbstractAction("Paste") { 
            /**
	     * 
	     */
	    private static final long serialVersionUID = 2055097051303850221L;

		public void actionPerformed(ActionEvent e) 
        	{ 
        		triangulationWindow.pasteVertices();
        	} 
        });
        editMenu.add(menuItem);
        editMenu.add(new JSeparator());
        menuItem = new JMenuItem("Mirror horizontally");
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, ActionEvent.SHIFT_MASK));
        menuItem.addActionListener(new AbstractAction("Mirror Horizontallly") { 
            /**
	     * 
	     */
	    private static final long serialVersionUID = -7129835335072726954L;


		public void actionPerformed(ActionEvent e) 
        	{ 
        		triangulationWindow.mirrorSelectedVerticesHorizontally();
        	} 
        });
      
        editMenu.add(menuItem); 
        menuItem = new JMenuItem("Mirror vertically");
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_UP, ActionEvent.SHIFT_MASK));
        menuItem.addActionListener(new AbstractAction("Mirror vertically") { 
            /**
	     * 
	     */
	    private static final long serialVersionUID = -2056389302031204261L;

	    public void actionPerformed(ActionEvent e) 
        	{ 
        		triangulationWindow.mirrorSelectedVerticesVertically();
        	} 
        });
        editMenu.add(menuItem);
        menuItem = new JMenuItem("Toggle Circles");
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.SHIFT_MASK));
        menuItem.addActionListener(new AbstractAction("Toggle Circles") { 
	    /**
	     * 
	     */
	    private static final long serialVersionUID = -5061539958733698876L;

	    public void actionPerformed(ActionEvent e) 
        	{ 
        		triangulationWindow.toggleShowCircles();
        	} 
        });
        editMenu.add(menuItem);
        editMenu.add(new JSeparator());
        menuItem = new JMenuItem("Deselect");
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.getKeyText(KeyEvent.VK_ESCAPE)));
        menuItem.addActionListener(new AbstractAction("Deselect") { 
	/**
	     * 
	     */
	    private static final long serialVersionUID = 648435360311851054L;

	public void actionPerformed(ActionEvent e) 
        	{ 
        		triangulationWindow.deselectVertices();
        	} 
        });
      
        editMenu.add(menuItem);
        menuItem = new JMenuItem("Remove selected");
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.getKeyText(KeyEvent.VK_DELETE)));
        menuItem.addActionListener(new AbstractAction("Remove selected") { 
   	/**
	     * 
	     */
	    private static final long serialVersionUID = 722083802369048339L;

	public void actionPerformed(ActionEvent e) 
        	{ 
        		triangulationWindow.deleteSelectedVertices();
        	} 
        });
        editMenu.add(menuItem);
        //
        // edit menu ends
        //
        this.setJMenuBar(menuBar);
        getContentPane().setLayout(new BorderLayout()); 
        //
        // menu Bar ends
        //
        triangulaters = new Vector<Triangulation.EdgeGenerator>(); 
        metrics = new Vector<MinimalityMetric>();
 
        windowNorth = new JPanel(); 
        windowNorth.setLayout(new BoxLayout(windowNorth, BoxLayout.X_AXIS)); 
        windowNorth.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 
        windowCenter = new JPanel(); 
        windowCenter.setBorder(BorderFactory.createEmptyBorder(0, 2, 2, 2)); 
        windowCenter.setLayout(new BoxLayout(windowCenter, BoxLayout.X_AXIS)); 
 
        triangulationWindow = new TriangleDisplay(this); 
        JScrollPane scrollPane = new JScrollPane(triangulationWindow);
        scrollPane.setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_AS_NEEDED);
        windowCenter.add(scrollPane); 
 
        clearButton = new JButton(new AbstractAction("Clear") 
        { 
            private static final long serialVersionUID = 9140613519878493935L; 
 
            public void actionPerformed(ActionEvent e) 
            { 
                triangulationWindow.reset(); 
            } 
        }); 
 
        randomGenerateButton = new JButton(new AbstractAction( 
                "Generate...") 
        { 
            private static final long serialVersionUID = 9140613519878493936L; 
 
            public void actionPerformed(ActionEvent e) 
            { 
                randomizePointsDialog();
            } 
        }); 
         
        triangulatersComboBox = new JComboBox(); 
        triangulatersComboBox.setAction(new AbstractAction() 
        { 
            private static final long serialVersionUID = 723646785157461810L; 
 
            public void actionPerformed(ActionEvent e) 
            { 
                activeTriangulater = triangulatersComboBox.getSelectedIndex();
                
                if (triangulaters != null && infoPanel != null)
                	infoPanel.setActiveTriangulator(triangulaters.elementAt(activeTriangulater));
                
                triangulationWindow.triangulate(true); 
            } 
        }); 
        
        metricsComboBox = new JComboBox(); 
        metricsComboBox.setAction(new AbstractAction() 
        { 
            private static final long serialVersionUID = 723646785157461810L; 
 
            public void actionPerformed(ActionEvent e) 
            { 
                activeMetric = metricsComboBox.getSelectedIndex();
                
                //if (triangulaters != null && infoPanel != null)
                //	infoPanel.setActiveTriangulator(triangulaters.elementAt(activeTriangulater));
                
                triangulationWindow.triangulate(true); 
            } 
        }); 
        
         
        String[] displayModes = { "All Edges", "LMT & Locally Minimal", "LMT Edges only"};
        displayModeComboBox = new JComboBox(displayModes);
        displayModeComboBox.setAction(new AbstractAction() 
        { 
            private static final long serialVersionUID = 723646784157461810L; 
 
            public void actionPerformed(ActionEvent e) 
            { 
                int mode = displayModeComboBox.getSelectedIndex();
                
                if (mode == 0) {
                	Globals.DRAW_EDGE_LMT_HOLE = true;
                	Globals.DRAW_EDGE_LOCALLY_MINIMAL = true;
                }
                else if (mode == 1) {
                 	Globals.DRAW_EDGE_LMT_HOLE = false;
                	Globals.DRAW_EDGE_LOCALLY_MINIMAL = true;
                }
                else {
                   	Globals.DRAW_EDGE_LMT_HOLE = false;
                	Globals.DRAW_EDGE_LOCALLY_MINIMAL = false;
                }

                triangulationWindow.redraw();
               
            } 
        }); 
        
        windowNorth.add(randomGenerateButton); 
        windowNorth.add(Box.createRigidArea(new Dimension(5, 10))); 
        windowNorth.add(clearButton); 
        windowNorth.add(Box.createRigidArea(new Dimension(10, 10))); 
        
        /*
        windowNorth.add(loadButton); 
        windowNorth.add(Box.createRigidArea(new Dimension(10, 10))); 
        windowNorth.add(saveButton); 
        windowNorth.add(Box.createRigidArea(new Dimension(10, 10))); 
        */
        windowNorth.add(new JLabel("Triangulation: ")); 
        windowNorth.add(triangulatersComboBox); 
        windowNorth.add(Box.createRigidArea(new Dimension(5, 10))); 
        windowNorth.add(metricsComboBox); 
        windowNorth.add(Box.createRigidArea(new Dimension(5, 10)));
        windowNorth.add(new JLabel("Display: ")); 
        windowNorth.add(displayModeComboBox); 

        
        getContentPane().add(windowNorth, BorderLayout.NORTH); 
        getContentPane().add(windowCenter, BorderLayout.CENTER); 
         
        randPointsDialog = new RandomizePointsDialog(this);
        saveVertsDialog = new SaveVerticesDialog(this);
        loadVertsDialog = new LoadVerticesDialog(this);
 
        setVisible(true); 
        
        addTriangulator(new Triangulation.ConvexHullEdgeGenerator());
        addTriangulator(new Triangulation.FastLMTTriangulator(false));
        addTriangulator(new Triangulation.FastLMTTriangulator(true)); 
//        addTriangulator(new Triangulation.SimpleLMTTriangulator( 
//                new OldShortestEdgesMetric())); 
        
        addMetric(new ShortestEdgesMetric());
        //addMetric(new AdjacentBaseToHeightRatioMetric());
        addMetric(new LongestBaseToHeightRatioMetric());
        addMetric(new LongestBaseToHeightRatioMetricDiamond());
        addMetric(new UniformAnglesMetric());
        addMetric(new DelaunayMetric());
        
        infoPanel = new BottomPanel();
        infoPanel.setTriangleDisplay(this.triangulationWindow);
        getContentPane().add(infoPanel, BorderLayout.PAGE_END); 
        
        if (showExtraInfo == false)
        	infoPanel.setVisible(false);
        
        doLayout();
    } 
 
    
    public void triangulate(Vector<Vertex> vertices) 
    { 
        if (triangulaters.size() > activeTriangulater && vertices.size() > 1) 
        { 
            Vertex[] aVertices = new Vertex[vertices.size()]; 
            vertices.toArray(aVertices); 
            triangulationWindow.showMesh(triangulaters.elementAt( 
                    activeTriangulater).processVertices(aVertices, getActiveMetric())); 
//            triangulationWindow.setVertices(vertices); 
        } 
        
        if (infoPanel != null)
        	infoPanel.repaint();
    }
    
    public EdgeGenerator getActiveTriangulator() {
    	return triangulaters.elementAt(activeTriangulater);
    }
    
    public MinimalityMetric getActiveMetric() {
    	return metrics.elementAt(activeMetric);
    }
 
    public void addTriangulator(Triangulation.EdgeGenerator t) 
    { 
        triangulaters.add(t); 
        triangulatersComboBox.addItem(t.getName()); 
    } 
    
    public void addMetric(MinimalityMetric metric)
    {
    	metrics.add(metric);
    	metricsComboBox.addItem(metric.getName());
    }
 
    public void randomizePointsDialog() 
    {     
        randPointsDialog.setVisible(true); 
    } 
    public void randomizePoints(int numPoints) 
    { 
    	triangulationWindow.spawnRandomPoints(numPoints); 
    }
    
    public void saveVerticesDialog() 
    {     
        saveVertsDialog.showSaveDialog(); 
    } 
    public void saveVertices(String state) 
    { 
    	triangulationWindow.spawnSavePoints(state);
    }
    
    public void loadVerticesDialog() 
    {     
        loadVertsDialog.showLoadDialog(); 
    } 
    public void loadVertices(String state) 
    { 
    	triangulationWindow.spawnLoadPoints(state); 
    }
    
    public BottomPanel getBottomPanel() {
    	return infoPanel;
    }
}
